身處後端開發一定會接觸到寫code去操作資料庫的需求,所以今天主題來介紹一點實務應用,透過Golang操作mysql資料庫,程式如何控制事務的提交與回滾&資料異動操作~
連線資料庫設置
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
//Init connect object. content-> account:password@tcp(host_ip:port)/db_name
dbu, err := sql.Open("mysql", "root:1234@tcp(127.0.0.1:3306)/user?charset=utf8&parseTime=True")
if err != nil {
fmt.Println("open mysql error", err)
return
}
//close conn.
defer dbu.Close()
//Create mysql connect.
err = dbu.Ping()
if err != nil {
fmt.Println("create mysql connect error", err)
return
}
/*
>以下連接池設定
注意點:
(1.)mysql連線預設保存時間為8小時,閒置超過8小時會被mysql斷開變失效連線。
查詢: show variables like '%wait_timeout%';
注意: 使用到被mysql斷開的連線會產生ERROR -> packets.go:36: unexpected EOF
(2.)mysql最大連線數。
查詢: show variables like '%max_connections%';
*/
//設置最大併發連線數,超過連線數需等待,直到其中連接被釋放並變為空閒。
dbu.SetMaxOpenConns(100)
//設置最大的空閒連接數,適當的設定空閒連接數(會佔用內存)將提高性能,減少從頭建立新連接的可能。
dbu.SetMaxIdleConns(10)
//設置連線的生命週期,過期後無法重用。
dbu.SetConnMaxLifetime(30)
}
(1.)建立資料庫
CREATE DATABASE user;
(2.)建立資料表
CREATE TABLE `user_lists` (
`user_id` bigint(20) NOT NULL COMMENT '使用者ID',
`account` varchar(50) NOT NULL COMMENT '帳號',
`level` tinyint(5) NOT NULL COMMENT '層級',
`last_login_time` int(11) NOT NULL COMMENT '最後登入時間',
`create_time` int(11) NOT NULL COMMENT '建立時間',
PRIMARY KEY (`user_id`)
);
進入正題~透過mysql driver對user_list這張表進行資料存取操作。
//異動數據 ( 新增/刪除/更新 )
func ExecSQL(dbu *sql.DB) error {
//INSERT INTO user_list(user_id,account,level,last_login_time,create_time) values(8723131, "siangx", 1, 1630385990, 1530385990);
sql := "INSERT INTO user_list(user_id,account,level,last_login_time,create_time) values(?,?,?,?,?)"
res, err := dbu.Exec(sql, 8723131, "siangx", 1, 1630385990, 1530385990)
if err != nil {
fmt.Println("insert user table error", err)
return err
}
//返回執行影響筆數
count, err := res.RowsAffected()
if err != nil {
fmt.Println("get RowsAffected error", err)
return err
}
fmt.Printf("[OK] %d row affected ", count)
return nil
}
//查詢數據
func QuerySQL(dbu *sql.DB) {
//先定義欲搜尋欄位的資料結構
type User struct {
UserID int64
Account string
Level int
}
/*
var userLists User
//單筆查詢
if err := dbu.QueryRow("SELECT user_id,account,level FROM user_list WHERE user_id = ?", 8723131).
Scan(&userLists.UserID, &userLists.Account, &userLists.Level); err != nil {
fmt.Println("query user table error", err)
}
log.Println(userLists)
*/
//查詢內容可能包含一筆(含)以上使用Query
//定義好要回傳的欄位結構
var userList []User
//send query sql to mysql
rows, err := dbu.Query("SELECT user_id,account,level FROM user_list WHERE user_id = ?", 8723131)
if err != nil {
fmt.Println("query user table error", err)
}
// close sql.Rows -> 重要: 記得要有這個動作去手動釋放連線。
defer rows.Close()
//read sql response rows -> 遍歷讀取出來的row資訊存入定義好的User結構
for rows.Next() {
user := User{}
err := rows.Scan(&user.UserID, &user.Account, &user.Level)
if err != nil {
fmt.Println("get user row data error", err)
}
userList = append(userList, user)
}
fmt.Printf("query response: %+v:", userList)
}
最後是我們的Transaction~
還記得前面我們提到用MYSQL CLI手動執行一個事務流程吧,現在換用程式來控制。
複習一下:
明天寫一個簡單的應用流程來說明事務提交流程~